@@ -44,6 +44,7 @@ gem 'simple_form' |
||
| 44 | 44 |
gem 'bootstrap_form' |
| 45 | 45 |
gem 'friendly_id', '~> 5.0.0' |
| 46 | 46 |
gem 'devise' |
| 47 |
+gem "devise-async" |
|
| 47 | 48 |
gem "letter_opener", :group => :development |
| 48 | 49 |
gem 'redcarpet' |
| 49 | 50 |
gem 'summernote-rails' |
@@ -71,6 +71,8 @@ GEM |
||
| 71 | 71 |
railties (>= 3.2.6, < 5) |
| 72 | 72 |
thread_safe (~> 0.1) |
| 73 | 73 |
warden (~> 1.2.3) |
| 74 |
+ devise-async (0.9.0) |
|
| 75 |
+ devise (~> 3.2) |
|
| 74 | 76 |
diff-lcs (1.2.5) |
| 75 | 77 |
email_spec (1.6.0) |
| 76 | 78 |
launchy (~> 2.1) |
@@ -291,6 +293,7 @@ DEPENDENCIES |
||
| 291 | 293 |
cucumber-rails |
| 292 | 294 |
database_cleaner |
| 293 | 295 |
devise |
| 296 |
+ devise-async |
|
| 294 | 297 |
email_spec |
| 295 | 298 |
factory_girl_rails (~> 4.0) |
| 296 | 299 |
figaro |
@@ -1,7 +1,7 @@ |
||
| 1 | 1 |
class User < ActiveRecord::Base |
| 2 | 2 |
# Include default devise modules. Others available are: |
| 3 | 3 |
# :confirmable, :lockable, :timeoutable and :omniauthable |
| 4 |
- devise :database_authenticatable, :registerable, |
|
| 4 |
+ devise :database_authenticatable, :async, :registerable, |
|
| 5 | 5 |
:recoverable, :rememberable, :trackable, :validatable |
| 6 | 6 |
|
| 7 | 7 |
validates :password, presence: true, length: {minimum: 5, maximum: 120}, on: :create
|
@@ -6,7 +6,7 @@ class SubscribeToMailchimp |
||
| 6 | 6 |
# Get User |
| 7 | 7 |
subscription = Subscription.find_by_id(id) |
| 8 | 8 |
|
| 9 |
- return true if (Rails.env.test? && !testing) |
|
| 9 |
+ return true if (Rails.env.test?) |
|
| 10 | 10 |
list_id = ENV['MAILCHIMP_LIST_ID'] |
| 11 | 11 |
response = Rails.configuration.mailchimp.lists.subscribe({
|
| 12 | 12 |
id: list_id, |
@@ -0,0 +1,2 @@ |
||
| 1 |
+# require "#{Rails.root}/features/support/cucumber_external_resque_worker"
|
|
| 2 |
+# CucumberExternalResqueWorker.install_hooks_on_startup |
@@ -13,7 +13,7 @@ Devise.setup do |config| |
||
| 13 | 13 |
config.mailer_sender = ENV['SERVER_EMAIL'] |
| 14 | 14 |
|
| 15 | 15 |
# Configure the class responsible to send e-mails. |
| 16 |
- # config.mailer = 'Devise::Mailer' |
|
| 16 |
+ #config.mailer = 'Devise::Mailer' |
|
| 17 | 17 |
|
| 18 | 18 |
# ==> ORM configuration |
| 19 | 19 |
# Load and configure the ORM. Supports :active_record (default) and |
@@ -0,0 +1,6 @@ |
||
| 1 |
+# config/initializers/devise_async.rb |
|
| 2 |
+Devise::Async.setup do |config| |
|
| 3 |
+ config.enabled = true |
|
| 4 |
+ config.backend = :resque |
|
| 5 |
+ config.queue = :send_reset_password |
|
| 6 |
+end |
@@ -0,0 +1 @@ |
||
| 1 |
+Resque.inline = Rails.env.test? |
@@ -60,6 +60,9 @@ Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([ |
||
| 60 | 60 |
# @email = ActionMailer::Base.deliveries.last |
| 61 | 61 |
# @email.to.should include address |
| 62 | 62 |
# @email.subject.should subject |
| 63 |
+ # CucumberExternalResqueWorker.reset_counter |
|
| 64 |
+ # Resque.remove_queue(:send_contact_message_queue) |
|
| 65 |
+ # CucumberExternalResqueWorker.process_all |
|
| 63 | 66 |
unread_emails_for(address).select { |m| m.subject =~ Regexp.new(Regexp.escape(subject)) }.size.should == parse_email_count(amount)
|
| 64 | 67 |
end |
| 65 | 68 |
|
@@ -0,0 +1,125 @@ |
||
| 1 |
+# This is adapted from this gist: https://gist.github.com/532100 by Square |
|
| 2 |
+# The main difference is that it doesn't require Bluth for WorkerBase |
|
| 3 |
+# It also calls prune_dead_workers on start so it doesn't hang on every other run |
|
| 4 |
+# It does not do anything special to avoid connecting to your main redis instance; you should be |
|
| 5 |
+# doing that elsewhere |
|
| 6 |
+ |
|
| 7 |
+class CucumberExternalResqueWorker |
|
| 8 |
+ DEFAULT_STARTUP_TIMEOUT = 1.minute |
|
| 9 |
+ COUNTER_KEY = "cucumber:counter" |
|
| 10 |
+ |
|
| 11 |
+ class << self |
|
| 12 |
+ attr_accessor :pid, :startup_timeout |
|
| 13 |
+ |
|
| 14 |
+ def start |
|
| 15 |
+ # Call from a Cucumber support file so it is run on startup |
|
| 16 |
+ return unless Rails.env.test? |
|
| 17 |
+ if self.pid = fork |
|
| 18 |
+ start_parent |
|
| 19 |
+ wait_for_worker_to_start |
|
| 20 |
+ else |
|
| 21 |
+ start_child |
|
| 22 |
+ end |
|
| 23 |
+ end |
|
| 24 |
+ |
|
| 25 |
+ def install_hooks_on_startup |
|
| 26 |
+ # Call from a Rails initializer |
|
| 27 |
+ return unless Rails.env.test? |
|
| 28 |
+ # Because otherwise crashed workers cause a fork and we pause the actual worker forever |
|
| 29 |
+ Resque::Worker.all.each { |worker| worker.prune_dead_workers }
|
|
| 30 |
+ install_pause_on_start_hook |
|
| 31 |
+ install_worker_base_counter_patch |
|
| 32 |
+ end |
|
| 33 |
+ |
|
| 34 |
+ def process_all |
|
| 35 |
+ # Call from a Cucumber step |
|
| 36 |
+ unpause |
|
| 37 |
+ sleep 1 until done? |
|
| 38 |
+ pause |
|
| 39 |
+ end |
|
| 40 |
+ |
|
| 41 |
+ def incr |
|
| 42 |
+ Resque.redis.incr(COUNTER_KEY) |
|
| 43 |
+ end |
|
| 44 |
+ |
|
| 45 |
+ def decr |
|
| 46 |
+ Resque.redis.decr(COUNTER_KEY) |
|
| 47 |
+ end |
|
| 48 |
+ |
|
| 49 |
+ def reset_counter |
|
| 50 |
+ Resque.redis.set(COUNTER_KEY, 0) |
|
| 51 |
+ end |
|
| 52 |
+ |
|
| 53 |
+ private |
|
| 54 |
+ |
|
| 55 |
+ def done? |
|
| 56 |
+ Resque.redis.get(CucumberExternalResqueWorker::COUNTER_KEY).to_i.zero? |
|
| 57 |
+ end |
|
| 58 |
+ |
|
| 59 |
+ def pause(pid = self.pid) |
|
| 60 |
+ return unless Rails.env.test? |
|
| 61 |
+ Process.kill("USR2", pid)
|
|
| 62 |
+ end |
|
| 63 |
+ |
|
| 64 |
+ def unpause |
|
| 65 |
+ return unless Rails.env.test? |
|
| 66 |
+ Process.kill("CONT", pid)
|
|
| 67 |
+ end |
|
| 68 |
+ |
|
| 69 |
+ def start_parent |
|
| 70 |
+ at_exit do |
|
| 71 |
+ #reset_counter |
|
| 72 |
+ Process.kill("KILL", pid) if pid
|
|
| 73 |
+ end |
|
| 74 |
+ end |
|
| 75 |
+ |
|
| 76 |
+ def start_child |
|
| 77 |
+ # Array form of exec() is required here, otherwise the worker is not a direct child process of cucumber. |
|
| 78 |
+ # If it's not the direct child process then the PID returned from fork() is wrong, which means we can't |
|
| 79 |
+ # communicate with the worker. |
|
| 80 |
+ exec('rake', 'resque:work', "QUEUE=*", "RAILS_ENV=test", "VVERBOSE=1")
|
|
| 81 |
+ end |
|
| 82 |
+ |
|
| 83 |
+ def wait_for_worker_to_start |
|
| 84 |
+ self.startup_timeout ||= DEFAULT_STARTUP_TIMEOUT |
|
| 85 |
+ start = Time.now.to_i |
|
| 86 |
+ while (Time.now.to_i - start) < startup_timeout |
|
| 87 |
+ return if worker_started? |
|
| 88 |
+ sleep 1 |
|
| 89 |
+ end |
|
| 90 |
+ |
|
| 91 |
+ raise "Timeout while waiting for the worker to start. Waited #{startup_timeout} seconds."
|
|
| 92 |
+ end |
|
| 93 |
+ |
|
| 94 |
+ def worker_started? |
|
| 95 |
+ Resque.info[:workers].to_i > 0 |
|
| 96 |
+ end |
|
| 97 |
+ |
|
| 98 |
+ def install_pause_on_start_hook |
|
| 99 |
+ Resque.before_first_fork do |
|
| 100 |
+ #reset_counter |
|
| 101 |
+ pause(Process.pid) |
|
| 102 |
+ end |
|
| 103 |
+ end |
|
| 104 |
+ |
|
| 105 |
+ def install_worker_base_counter_patch |
|
| 106 |
+ Resque.class_eval do |
|
| 107 |
+ class << self |
|
| 108 |
+ def enqueue_with_counters(*args, &block) |
|
| 109 |
+ CucumberExternalResqueWorker.incr |
|
| 110 |
+ enqueue_without_counters(*args, &block) |
|
| 111 |
+ end |
|
| 112 |
+ alias_method_chain :enqueue, :counters |
|
| 113 |
+ end |
|
| 114 |
+ end |
|
| 115 |
+ Resque::Job.class_eval do |
|
| 116 |
+ def perform_with_counters(*args, &block) |
|
| 117 |
+ perform_without_counters(*args, &block) |
|
| 118 |
+ ensure |
|
| 119 |
+ CucumberExternalResqueWorker.decr |
|
| 120 |
+ end |
|
| 121 |
+ alias_method_chain :perform, :counters |
|
| 122 |
+ end |
|
| 123 |
+ end |
|
| 124 |
+ end |
|
| 125 |
+end |
@@ -6,6 +6,9 @@ |
||
| 6 | 6 |
|
| 7 | 7 |
require 'cucumber/rails' |
| 8 | 8 |
|
| 9 |
+# require "#{Rails.root}/features/support/cucumber_external_resque_worker"
|
|
| 10 |
+# CucumberExternalResqueWorker.start |
|
| 11 |
+ |
|
| 9 | 12 |
# Capybara defaults to CSS3 selectors rather than XPath. |
| 10 | 13 |
# If you'd prefer to use XPath, just uncomment this line and adjust any |
| 11 | 14 |
# selectors in your step definitions to use the XPath syntax. |
@@ -31,7 +34,7 @@ ActionController::Base.allow_rescue = false |
||
| 31 | 34 |
# Remove/comment out the lines below if your app doesn't have a database. |
| 32 | 35 |
# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. |
| 33 | 36 |
begin |
| 34 |
- DatabaseCleaner.strategy = :transaction |
|
| 37 |
+ DatabaseCleaner.strategy = :truncation |
|
| 35 | 38 |
rescue NameError |
| 36 | 39 |
raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." |
| 37 | 40 |
end |
@@ -66,3 +69,5 @@ require "#{Rails.root}/spec/spec_helper"
|
||
| 66 | 69 |
ActionMailer::Base.delivery_method = :test |
| 67 | 70 |
ActionMailer::Base.perform_deliveries = true |
| 68 | 71 |
ActionMailer::Base.deliveries.clear |
| 72 |
+ |
|
| 73 |
+ |